package com.school.springboot_login.aspect;


import com.school.springboot_login.annotation.LogAnnotation;
import com.school.springboot_login.bean.AopLog;
import com.school.springboot_login.bean.User;
import com.school.springboot_login.service.AopLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/*
* 切面类
*    对于用户登录和注册之后的行为进行增强
* */
//Component相当于把不属于controller,service,dao三个层的类用这个标注，
//被@controller 、@service、@repository 、@component 注解的类，都会把这些类纳入进spring容器中进行管理
//将对象交给IOC容器进行实例化
@Component
//定义切面类
@Aspect
public class LogAspect {
    /*@Resource和@Autowired注解都是用来实现依赖注入的。只是@AutoWried按by type自动注入，而@Resource默认按byName自动注入。*/
    //注入service用于把日志保存数据库
    @Resource
    private AopLogService logService;
    //切入点定义:切入点指示符用来指示切入点表达式目的
    // execution：用于匹配方法执行的连接点；
    //controller切入点,定义在controller下的LoginController类的任意方法的执行
    @Pointcut("execution(* com.school.springboot_login.controller.LoginController.*(..))")
    public void logAspect() {
        System.out.println("---------------------logAspect for log start----------------------------");
    }


    //返回通知
    @AfterReturning(value="logAspect()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("-----返回通知-----");
        //通过RequestControllerHolder直接获取HttpServletRequest对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        try {
            //获取注解中对方法的描述信息，用于Controller层的注解，该方法在下面有定义
            String methodDesc = getControllerMethodDescription(joinPoint);
            //目标方法名
            System.out.println("request method : " + joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
            //获取当前切入点中注解的操作是什么
            System.out.println("method description : " + methodDesc);
            //输出成功插入数据库
            System.out.println("insert log infos into db start");
            //日志初始化
            AopLog aopLog=new AopLog();
            //执行日志入库操作
            //获取注解的信息

            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            Method method = ms.getMethod();
            LogAnnotation log = method.getAnnotation(LogAnnotation.class);

            //判断方法描述是否是用户注册
            if(methodDesc.equals("用户注册"))
            {
                System.out.println(methodDesc);
                //request.getSession().setAttribute和request.getSession().getAttribute()就是分别对session对象赋值和得到对象属性的值。
                //user1 在controller中对于session对象进行赋值
                User user1 = (User) request.getSession().getAttribute("user1");
                //获取session属性的值并对日志进行赋值
                aopLog.setUser_id(user1.getUserId());
                aopLog.setUser_name(user1.getUserName());
                aopLog.setModuleName(log.moduleName());
                aopLog.setOperationDesc(log.option());
                aopLog.setCreateTime(new Date());
                System.out.println("request username : " + (user1 == null ? "no login info found" : user1.getUserName()));
                logService.insertAopLog(aopLog);
                System.out.println("insert log infos into db successful.");
            }
            else if(methodDesc.equals("用户登录"))
            {
                System.out.println("用户登录");
                User user = (User) request.getSession().getAttribute("user");
                System.out.println(user.getUserId());
                aopLog.setUser_id(user.getUserId());
                aopLog.setUser_name(user.getUserName());
                aopLog.setModuleName(log.moduleName());
                aopLog.setOperationDesc(log.option());
                aopLog.setCreateTime(new Date());
                System.out.println("request username : " + (user == null ? "no login info found" : user.getUserName()));
                logService.insertAopLog(aopLog);
                System.out.println("insert log infos into db successful.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取方法的描述
     */

    private String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
        //获取目标类名
        String targetName = joinPoint.getTarget().getClass().getName();
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取相关参数
        Object[] arguments = joinPoint.getArgs();
        //生成类对象
        Class targetClass = Class.forName(targetName);
        //获取该类中的方法
        Method[] methods = targetClass.getMethods();
        String description = "";
        //对于方法进行循环
        for (Method method : methods) {
            //判断当前方法名是否等于切点位置的方法名，不相等，就继续。
            if (!method.getName().equals(methodName)) {
                continue;
            }
            //判断方法中的参数是否相等，不相等就继续循环
            Class[] clazzs = method.getParameterTypes();
            if (clazzs.length != arguments.length) {
                continue;
            }
            //description对应的就是自定义注释中的option
           // description =method.getAnnotation(LogAnnotation.class).option();
            //判断当前的自定义的操作是否为空
            description +=method.getAnnotation(LogAnnotation.class)==null?"还未获取操作":method.getAnnotation(LogAnnotation.class).option();
        }
        return description;
    }
}


